//---------------------------------------------------------------------
// Author: Keith Hill
//
// Description: Class to parse through the PE header of an executable
//              to find out some simple info like if the file is an
//              assembly.  This is by no means a thorough PE
//
//              Current implementation comes from:
//              http://geekswithblogs.net/rupreet/archive/2005/11/02/58873.aspx
//              and
//              http://www.bearcanyon.com/dotnet/#AssemblyParser
//
// Creation Date: Dec 18, 2006
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Pscx
{
    [Obsolete("Use the Pscx.Commands.Reflection.PortableExecutable class")]
    public static class PEHeaderParser
    {
        private const int OffsetToPEHeaderOffset = 0x3c;

        public static PEHeaderInfo ScanFile(string path)
        {
            if (!File.Exists(path))
            {
                string msg = String.Format(Resources.Shared.ExpectedPathToFile_Fmt1, path);
                throw new ArgumentException(msg, "path");
            }

            PEHeaderInfo headerInfo = new PEHeaderInfo();

            using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                BinaryReader reader = new BinaryReader(fileStream);

                // Verify that file starts with "MZ" signature
                ushort signature = reader.ReadUInt16();
                if (signature != 0x5a4d)
                {
                    string msg = String.Format(Resources.Messages.PEHdrParserInvalidExe_Fmt1, path);
                    throw new ArgumentException(msg, "path");
                }

                // Move to beginning of PE header and verify that it starts with 'PE\0\0'
                fileStream.Position = OffsetToPEHeaderOffset;
                uint peHeaderPosition = reader.ReadUInt32();
                fileStream.Position = peHeaderPosition;
                uint peSignature = reader.ReadUInt32();
                if (peSignature != 0x00004550)
                {
                    string msg = String.Format(Resources.Messages.PEHdrParserInvalidExe_Fmt1, path);
                    throw new ArgumentException(msg, "path");
                }

                ushort machineCode = reader.ReadUInt16();
                if (machineCode != 0x014c)
                {
                    // Invalid or unrecognized PE file of some kind.
                    string msg = String.Format(Resources.Messages.PEHdrParserInvalidExe_Fmt1, path);
                    throw new ArgumentException(msg, "path");
                }

                ushort sections = reader.ReadUInt16();
                uint timestamp = reader.ReadUInt32();
                uint pSymbolTable = reader.ReadUInt32();
                uint numberOfSymbol = reader.ReadUInt32();
                ushort optionalHeaderSize = reader.ReadUInt16();
                ushort characteristics = reader.ReadUInt16();

                ushort dataDictionaryStart = Convert.ToUInt16(Convert.ToUInt16(fileStream.Position) + 0x60);
                fileStream.Position = dataDictionaryStart;
                uint[] dataDictionaryRVA = new uint[16];
                uint[] dataDictionarySize = new uint[16];

                for (int i = 0; i < 15; i++)
                {
                    dataDictionaryRVA[i] = reader.ReadUInt32();
                    dataDictionarySize[i] = reader.ReadUInt32();
                }

                headerInfo.IsAssembly = (dataDictionaryRVA[14] != 0);
            }

            return headerInfo;
        }
    }
}
